package com.gitee.zw.irmp.common.auth;

import com.gitee.zw.irmp.common.auth.session.UserSessionStore;
import com.gitee.zw.irmp.common.auth.sso.SSOProcessor;
import com.gitee.zw.irmp.common.auth.vo.LoginUser;
import com.gitee.zw.irmp.common.exception.AuthenticationException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.GenericFilterBean;

import java.io.IOException;

@Slf4j
@Component
@Order(20)
@WebFilter(servletNames = "dispatcherServlet")
@ConfigurationProperties(prefix = "app.irmp.common.auth.jwt")
public class JWTFilter extends GenericFilterBean {

    @Autowired
    private UserSessionStore userSessionStore;

    private AntPathMatcher matcher = new AntPathMatcher();
    @Setter
    private String[] excludePaths;

    @Value("${app.irmp.common.system.user-code}")
    private String riskUserCode = "rwa0001";;

    @Override
    public void doFilter(ServletRequest request1, ServletResponse response1, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) request1;
        String uri =request.getRequestURI();
        String contextPath = request.getContextPath();
        if (contextPath != null && contextPath.length() > 0) {
            uri = uri.substring(contextPath.length());
        }
        if (isExcludePath(uri)) {
            chain.doFilter(request1, response1);
            return;
        }
//        HttpServletResponse response = (HttpServletResponse) response1;
        String token = getToken(request);
        if (token != null && !token.isEmpty()) {
            LoginUser loginUser = null;

            if (riskUserCode.equals(token)) {
                loginUser = new LoginUser();
                loginUser.setUsername(riskUserCode);
                loginUser.setDisplayName(riskUserCode);
            } else {
                try {
                    loginUser = userSessionStore.getLoginUser(token);
                } catch (Exception e) {
                    log.error("Error to get user", e);
                    throw new AuthenticationException(e);
                }
            }
            if (loginUser != null) {
//                setAuthHeader(token, response);
                AuthUtils.setLoginUser(loginUser);
                chain.doFilter(request1, response1);
                return;
            } else {
                String msg = "User not found in session, maybe session out?";
                log.warn(msg);
                throw new AuthenticationException(msg);
            }
        }
        throw new AuthenticationException("User has not login, no token found.");
    }

    private boolean isExcludePath(String uri) {
        for (String excludePath : excludePaths) {
            if (matcher.match(excludePath, uri)) {
                return true;
            }
        }
        return false;
    }

    public static void setAuthHeader(String token, HttpServletResponse response) {
        Cookie cookie = new Cookie(SSOProcessor.AUTH_COOKIE_NAME, token);
        cookie.setPath("/");
        response.addCookie(cookie);
        response.setHeader(SSOProcessor.AUTH_COOKIE_NAME, "Bearer " + token);
    }

    public static String getToken(HttpServletRequest request) {
        String token = request.getHeader(SSOProcessor.AUTH_COOKIE_NAME);
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
        } else {
            token = (String) request.getAttribute(SSOProcessor.AUTH_COOKIE_NAME);
            if (token == null) {
                Cookie[] cookies = request.getCookies();
                if (cookies != null) {
                    for (Cookie cookie : cookies) {
                        if (cookie.getName().equals(SSOProcessor.AUTH_COOKIE_NAME)) {
                            token = cookie.getValue();
                            break;
                        }
                    }
                }
            }

        }
        return token;
    }


}
